package com.codeberry.yws;

import static com.codeberry.yws.Response.ErrorType.OK;
import com.codeberry.yws.exception.HeaderWriteException;
import com.codeberry.yws.exception.ResponseFlushException;

import java.io.BufferedOutputStream;
import java.io.IOException;
import java.text.SimpleDateFormat;
import java.util.Calendar;
import java.util.Date;
import java.util.SimpleTimeZone;

public class Response {
  private static final SimpleDateFormat FORMAT = new SimpleDateFormat("d MMM yyyy HH:mm:ss 'GMT'");
  private static final Calendar CAL_GMT = Calendar.getInstance(new SimpleTimeZone(0, "GMT"));

  static {
    FORMAT.setCalendar(CAL_GMT);
  }

  private final BufferedOutputStream output;

  private String contentType;
  private long contentLength;
  private long lastModified;
  private ErrorType errorType;

  public Response(BufferedOutputStream output) {
    this.output = output;

    errorType = OK;
  }

  public void setContentType(String contentType) {
    this.contentType = contentType;
  }

  public void setContentLength(long contentLength) {
    this.contentLength = contentLength;
  }

  public void setLastModified(long lastModified) {
    this.lastModified = lastModified;
  }

  public BufferedOutputStream ready() {
    writeHeader();
    return output;
  }

  private void writeHeader() {
    String header = makeHeader();
    try {
      output.write(header.getBytes());
    } catch (IOException e) {
      throw new HeaderWriteException();
    }
  }

  private String makeHeader() {
    return "HTTP/1.0 " + errorType.getCode() + " " + errorType.getMessage() + "\r\n" +
           "Server: Yocto Web Server/1.0\r\n" +
           "Date: " + FORMAT.format(new Date()) + "\r\n" +
           (lastModified >= 0 ? "Last-modified: " + FORMAT.format(new Date(lastModified)) + "\r\n" : "") +
           "MIME-version: 1.0\r\n" +
           (contentType != null ? "Content-type: " + contentType + "\r\n" : "") +
           (contentLength >= 0 ? "Content-length: " + contentLength + "\r\n" : "") +
           "\r\n";
  }

  public void setError(ErrorType errorType) {
    this.errorType = errorType;
  }

  public void flush() {
    try {
      output.flush();
    } catch (IOException e) {
      throw new ResponseFlushException();
    }
  }

  public static enum ErrorType {
    OK {
      public int getCode() {
        return 200;
      }
      public String getMessage() {
        return "OK";
      }
    },
    FILE_NOT_FOUND {
      public int getCode() {
        return 404;
      }

      public String getMessage() {
        return "FILENOTFOUND";
      }
    };

    public abstract int getCode();
    public abstract String getMessage();
  }
}
